﻿
using System;
using System.Windows;


// Stubs used for testing code generation.
namespace Boilen.Primitives.CodeGeneration {

#if SL3_0
    public interface IFreezable {
        bool IsFrozen { get; }
        void Freeze( );
        event EventHandler SubpropertyChanged;
    }
#endif

}

namespace Boilen.Freezables {

#if SL3_0
    using Freezable = FrameworkElement;
#endif

    public class FreezableImpl : Freezable
#if SL3_0
    , Boilen.Primitives.CodeGeneration.IFreezable {
        #region IFreezable Members
        public bool IsFrozen { get; private set; }
        public void Freeze( ) {
            this.FreezeProperties( );
            this.IsFrozen = true;
        }

        private event EventHandler subpropertyChanged_;
        event EventHandler Boilen.Primitives.CodeGeneration.IFreezable.SubpropertyChanged {
            add { this.subpropertyChanged_ += value; }
            remove { this.subpropertyChanged_ -= value; }
        }
        protected void OnSubpropertyChanged() {
            var h = this.subpropertyChanged_;
            if( h != null ) { h( this, EventArgs.Empty ); }
        }

        protected virtual void FreezeProperties( ) { }
        protected static T FreezeValue<T>( T value ) {
            var freezable = value as Boilen.Primitives.CodeGeneration.IFreezable;
            if( freezable != null )
                freezable.Freeze( );
            return value;
        }
        #endregion
#else
    {
        protected override Freezable CreateInstanceCore( ) {
            return new FreezableImpl( );
        }
#endif
    }

    public static class FreezableExtensions {
        public static T SafeFreeze<T>( this T value )
#if SL3_0
        where T : class {
            var freezable = value as Boilen.Primitives.CodeGeneration.IFreezable;
#else
        where T : Freezable {
            var freezable = value;
#endif
            if( freezable != null )
                freezable.Freeze( );
            return value;
        }

#if SL3_0
        public static void SafeSubpropertyChanged( this object value, EventHandler handler, bool subscribe ) {
            var freezable = value as Boilen.Primitives.CodeGeneration.IFreezable;
            if( freezable != null ) {
                if( subscribe )
                    freezable.SubpropertyChanged += handler;
                else
                    freezable.SubpropertyChanged -= handler;
            }
        }
#endif
    }

}

namespace Boilen.Guards {

    public static class TestGuards {
        private static readonly TestGuardContext Context = new TestGuardContext( );
        public static object UseContext( Func<object> act, Action<TestGuardContext> test ) {
            Context.Reset( );
            var result = act( );
            test( Context );
            return result;
        }
        public static void UseContext( Action act, Action<TestGuardContext> test ) {
            UseContext( ( ) => { act( ); return null; }, test );
        }

        public static TestGuard GuardParam<T>( this T value, string paramName ) { return new TestGuard( ); }
        public static TestGuard GuardValue<T>( this T value, string valueName ) { return new TestGuard( ); }

        public struct TestGuard {
            public TestGuard NotNull( ) {
                Context.NotNullCalled = true;
                return this;
            }
            public TestGuard Satisfies( bool condition, string format, params object[] args ) { return this; }
        }

        public sealed class TestGuardContext {
            public bool NotNullCalled { get; set; }

            public void Reset( ) {
                var properties = typeof( TestGuardContext ).GetProperties( );
                foreach( var property in properties ) {
                    property.SetValue( this, false, null );
                }
            }
        }
    }

}

namespace Boilen.Validations {

    public static class DependencyPropertyCallbacks {
        public static object CoerceNonNegative<T>( DependencyObject d, object baseValue ) { return baseValue; }
        public static bool IsValidEnum<T>( object value ) { return true; }
        public static bool IsNotNull<T>( object value ) { return true; }

        public static object ExternalCoerceHandler( DependencyObject d, object baseValue ) { return baseValue; }
    }

}
